﻿namespace ReplayDataFile
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;

    public class BlockAllocateTable
    {
        private BlockInfo[] blockInfos;

        public BlockAllocateTable(int blockCount)
        {
            if (blockCount != 0)
            {
                this.blockInfos = new BlockInfo[blockCount];
                for (int i = 0; i < blockCount; i++)
                {
                    this.blockInfos[i] = new BlockInfo();
                }
                this.Init();
            }
        }

        public bool AllocBlock(int blockIndex, int preBlock, short dataVer)
        {
            this.WriteAllocTable(preBlock, blockIndex);
            return this.WriteAllocTable(blockIndex, -2, dataVer);
        }

        public bool FromByteBuffer(byte[] buf)
        {
            BinaryReader reader = new BinaryReader(new MemoryStream(buf));
            int num = reader.ReadInt32();
            int num2 = reader.ReadInt32();
            if (num2 < 0)
            {
                return false;
            }
            reader.ReadBytes(120);
            this.blockInfos = new BlockInfo[num2];
            for (int i = 0; i < num2; i++)
            {
                BlockInfo info = new BlockInfo();
                this.blockInfos[i] = info;
                info.AllocFlag = reader.ReadInt32();
                info.UsedSpace = reader.ReadInt32();
                info.DataVersion = reader.ReadInt16();
            }
            reader.Close();
            return true;
        }

        public List<int> GetAllocBlockList(int firstBlockIndex)
        {
            List<int> list = new List<int>();
            if (firstBlockIndex < 0)
            {
                return list;
            }
            if ((firstBlockIndex < 0) || (firstBlockIndex >= this.blockInfos.Length))
            {
                return list;
            }
            int item = firstBlockIndex;
            while (true)
            {
                if (list.Contains(item))
                {
                    return list;
                }
                list.Add(item);
                int allocFlag = this.blockInfos[item].AllocFlag;
                if ((allocFlag == -2) || (allocFlag < 0))
                {
                    return list;
                }
                item = allocFlag;
            }
        }

        public long GetBlockDataSize()
        {
            long num = 0L;
            foreach (BlockInfo info in this.blockInfos)
            {
                num += info.UsedSpace;
            }
            return num;
        }

        public BlockInfo GetBlockInfo(int blockIndex)
        {
            if ((blockIndex < 0) || (blockIndex > this.blockInfos.Length))
            {
                return null;
            }
            return this.blockInfos[blockIndex];
        }

        public int GetBlockUsedSpace(int blockIndex)
        {
            if ((blockIndex < 0) || (blockIndex >= this.blockInfos.Length))
            {
                return 0;
            }
            return this.blockInfos[blockIndex].UsedSpace;
        }

        public int GetFreeBlock()
        {
            int length = this.blockInfos.Length;
            for (int i = 0; i < length; i++)
            {
                if (this.blockInfos[i].AllocFlag == -1)
                {
                    return i;
                }
            }
            return -1;
        }

        public int GetFreeBlockCount()
        {
            int num = 0;
            int length = this.blockInfos.Length;
            for (int i = 0; i < length; i++)
            {
                if (this.blockInfos[i].AllocFlag == -1)
                {
                    num++;
                }
            }
            return num;
        }

        public int GetLastAllocBlock(int firstBlockIndex)
        {
            if (firstBlockIndex != -1)
            {
                List<int> allocBlockList = this.GetAllocBlockList(firstBlockIndex);
                if (allocBlockList.Count > 0)
                {
                    return allocBlockList[allocBlockList.Count - 1];
                }
            }
            return -1;
        }

        public bool GetMaxFreeRegion(ref int beginBlockIndex, ref int endBlockIndex)
        {
            int length = this.blockInfos.Length;
            if (length <= 0)
            {
                return false;
            }
            int num2 = -1;
            int num3 = -1;
            int num4 = -1;
            int num5 = -1;
            int num6 = -1;
            for (int i = 0; i < length; i++)
            {
                int allocFlag = this.blockInfos[i].AllocFlag;
                if (allocFlag == -1)
                {
                    if (num2 == -1)
                    {
                        num2 = i;
                    }
                    num3 = i;
                }
                if (((allocFlag != -1) || (i == (length - 1))) && (num3 != -1))
                {
                    int num9 = num3 - num2;
                    if (num9 > num6)
                    {
                        num6 = num9;
                        num4 = num2;
                        num5 = num3;
                    }
                    num2 = -1;
                    num3 = -1;
                }
            }
            beginBlockIndex = num4;
            endBlockIndex = num5;
            return ((beginBlockIndex != -1) && (endBlockIndex != -1));
        }

        public int GetNextFreeBlock(int blockIndex)
        {
            Debug.Assert(blockIndex >= 0);
            if (blockIndex >= 0)
            {
                int num3;
                int length = this.blockInfos.Length;
                int index = (blockIndex + 1) % length;
                if (this.blockInfos[index].AllocFlag == -1)
                {
                    return index;
                }
                for (num3 = index + 1; num3 < length; num3++)
                {
                    if (this.blockInfos[num3].AllocFlag == -1)
                    {
                        return num3;
                    }
                }
                for (num3 = 0; num3 < blockIndex; num3++)
                {
                    if (this.blockInfos[num3].AllocFlag == -1)
                    {
                        return num3;
                    }
                }
            }
            return -1;
        }

        public void Init()
        {
            foreach (BlockInfo info in this.blockInfos)
            {
                info.AllocFlag = -1;
                info.UsedSpace = 0;
                info.DataVersion = -1;
            }
        }

        public void InitDataBlock(int block)
        {
            BlockInfo blockInfo = this.GetBlockInfo(block);
            if (blockInfo != null)
            {
                blockInfo.AllocFlag = -1;
                blockInfo.DataVersion = -1;
                blockInfo.UsedSpace = 0;
            }
        }

        public byte[] ToByteBuffer()
        {
            byte[] buffer = new byte[this.Size];
            BinaryWriter writer = new BinaryWriter(new MemoryStream(buffer));
            writer.Write(buffer.Length);
            writer.Write(this.blockInfos.Length);
            writer.Write(new byte[120]);
            for (int i = 0; i < this.blockInfos.Length; i++)
            {
                BlockInfo info = this.blockInfos[i];
                writer.Write(info.AllocFlag);
                writer.Write(info.UsedSpace);
                writer.Write(info.DataVersion);
            }
            writer.Close();
            return buffer;
        }

        public bool WriteAllocTable(int blockIndex, int blockFlag)
        {
            if ((blockIndex < 0) || (blockIndex >= this.blockInfos.Length))
            {
                return false;
            }
            BlockInfo info = this.blockInfos[blockIndex];
            int allocFlag = info.AllocFlag;
            Debug.Assert((allocFlag == -1) || (allocFlag == -2));
            info.AllocFlag = blockFlag;
            return true;
        }

        public bool WriteAllocTable(int blockIndex, int blockFlag, short dataVer)
        {
            if ((blockIndex < 0) || (blockIndex >= this.blockInfos.Length))
            {
                return false;
            }
            BlockInfo info = this.blockInfos[blockIndex];
            int allocFlag = info.AllocFlag;
            Debug.Assert((allocFlag == -1) || (allocFlag == -2));
            info.DataVersion = dataVer;
            info.AllocFlag = blockFlag;
            return true;
        }

        public bool WriteBlockUsedSpace(int blockIndex, int usedSapce)
        {
            if ((blockIndex < 0) || (blockIndex >= this.blockInfos.Length))
            {
                return false;
            }
            this.blockInfos[blockIndex].UsedSpace = usedSapce;
            return true;
        }

        public int Count
        {
            get
            {
                return this.blockInfos.Length;
            }
        }

        public int Size
        {
            get
            {
                int num = 8 + (this.blockInfos.Length * BlockInfo.Size);
                return (((num + 0x3ff) / 0x400) * 0x400);
            }
        }
    }
}

